package cn.vehicle.biz.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import cn.vehicle.biz.SysUserBiz;
import cn.vehicle.domains.bo.QueryRoleBo;
import cn.vehicle.domains.bo.QueryUserBo;
import cn.vehicle.domains.entity.SysRoleEntity;
import cn.vehicle.domains.entity.SysUserEntity;
import cn.vehicle.domains.entity.SysUserRoleEntity;
import cn.vehicle.domains.info.UserInfo;
import cn.vehicle.domains.vo.BasePage;
import cn.vehicle.domains.vo.req.sysUser.*;
import cn.vehicle.domains.vo.res.sysPermission.SysPermissionRes;
import cn.vehicle.domains.vo.res.sysRole.SysRoleRes;
import cn.vehicle.domains.vo.res.sysUser.SysUserRes;
import cn.vehicle.enums.ActiveEnum;
import cn.vehicle.exception.VehicleAccessException;
import cn.vehicle.service.SysRoleService;
import cn.vehicle.service.SysUserRoleService;
import cn.vehicle.service.SysUserService;
import cn.vehicle.service.config.SystemConfig;
import cn.vehicle.service.config.SystemConfigService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 系统用户业务实现类
 * <p>
 * 负责用户的增删改查、角色关联、登录认证与 Token 生成等业务逻辑。
 * 主要职责包括：
 * <ul>
 *   <li>用户新增、修改、删除、分页查询；</li>
 *   <li>用户角色绑定与权限校验；</li>
 *   <li>用户登录与 JWT Token 签发；</li>
 *   <li>密码脱敏展示与默认密码设置。</li>
 * </ul>
 * </p>
 *
 * <p>设计约定：</p>
 * <ul>
 *   <li>所有用户写操作均调用 {@link SysUserService}；</li>
 *   <li>角色相关操作通过 {@link SysUserRoleService} 与 {@link SysRoleService} 协作完成；</li>
 *   <li>密码默认值从 {@link SystemConfig#defaultPassword} 获取；</li>
 *   <li>Token 加密密钥与过期时间由 {@link SystemConfig#jwtSecurityKey} 与 {@link SystemConfig#jwtTokenExpireTime} 控制。</li>
 * </ul>
 */
@Service
public class SysUserBizImpl implements SysUserBiz {

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysRoleService sysRoleService;


    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private SystemConfigService systemConfigService;

    @Override
    /**
     * 新增系统用户
     *
     * @param req 用户新增请求参数
     *            包含基本信息，密码设置为系统默认密码。
     */
    public void addUser(AddUserReq req) {

        SysUserEntity sysUserEntity = new SysUserEntity();
        BeanUtils.copyProperties(req, sysUserEntity);
        sysUserEntity.setPassword(systemConfigService.get(SystemConfig.defaultPassword));

        sysUserService.addUser(sysUserEntity);
    }

    /**
     * 更新系统用户信息
     *
     * @param req 用户更新请求参数，需包含用户ID
     * @throws VehicleAccessException 当用户不存在时抛出
     */
    @Override
    public void updateUser(UpdateUserReq req) {
        checkUserExist(req.getId());

        SysUserEntity updateEntity = new SysUserEntity();
        BeanUtils.copyProperties(req, updateEntity);
        sysUserService.updateUser(updateEntity);

    }


    /**
     * 删除系统用户
     *
     * @param id 用户主键ID
     * @throws VehicleAccessException 当用户不存在时抛出
     */
    @Override
    public void deleteUser(Long id) {
        checkUserExist(id);

        sysUserService.deleteUser(id);

    }

    /**
     * 根据ID查询用户详情
     *
     * @param id 用户主键ID
     * @return 用户详情信息（密码已脱敏）
     * @throws VehicleAccessException 当用户不存在时抛出
     */
    @Override
    public SysUserRes getUserById(Long id) {
        SysUserEntity sysUserEntity = checkUserExist(id);

        SysUserRes sysUserRes = new SysUserRes();
        BeanUtils.copyProperties(sysUserEntity, sysUserRes);
        String password = DesensitizedUtil.idCardNum(sysUserEntity.getPassword(), 2, 2);
        sysUserRes.setPassword(password);
        return sysUserRes;
    }

    /**
     * 分页查询用户列表
     *
     * <p>基于 PageHelper 实现分页。</p>
     *
     * @param req 查询条件与分页参数
     * @return 分页结果（密码脱敏）
     */
    @Override
    public BasePage<SysUserRes> list(UserListReq req) {

        Page<SysUserEntity> page = PageHelper.startPage(req.getPageNo(), req.getPageSize());


        QueryUserBo queryUserBo = new QueryUserBo();
        BeanUtils.copyProperties(req, queryUserBo);


        List<SysUserEntity> userEntityList = sysUserService.selectUserList(queryUserBo);
        List<SysUserRes> list = userEntityList.stream().map(sysUserEntity -> {
            SysUserRes sysUserRes = new SysUserRes();
            BeanUtils.copyProperties(sysUserEntity, sysUserRes);
            String password = DesensitizedUtil.idCardNum(sysUserEntity.getPassword(), 2, 2);
            sysUserRes.setPassword(password);
            return sysUserRes;
        }).toList();
        return BasePage.generateResult(page.getPages(), page.getTotal(), list);
    }

    /**
     * 绑定用户角色
     *
     * <p>逻辑说明：</p>
     * <ol>
     *   <li>校验用户存在性；</li>
     *   <li>若角色列表为空则清空所有绑定关系；</li>
     *   <li>校验角色合法性与启用状态；</li>
     *   <li>删除旧的角色关系，新增新的绑定关系。</li>
     * </ol>
     *
     * @param req 用户角色绑定请求参数
     * @throws VehicleAccessException 用户不存在或角色无效时抛出
     */
    @Override
    public void addUserRoles(AddUserRoleReq req) {
        //1 判断用户是否存在
        checkUserExist(req.getUserId());

        if (CollectionUtil.isEmpty(req.getRoleIds())) {
            sysUserRoleService.addUserRoles(req.getUserId(), null);
            return;
        }

        QueryRoleBo queryRoleBo = new QueryRoleBo();
        queryRoleBo.setIds(req.getRoleIds());
        queryRoleBo.setStatusList(Collections.singletonList(ActiveEnum.ACTIVE.name()));
        //3 校验角色是否合法
        List<SysRoleEntity> sysRoleEntityList = sysRoleService.selectRoleList(queryRoleBo);


        if (CollectionUtil.isEmpty(sysRoleEntityList)
            || req.getRoleIds().size() != sysRoleEntityList.size()) {
            throw VehicleAccessException.DATE_NOT_EXIST.newInstance("有角色id不存在");
        }

        List<SysUserRoleEntity> list = new ArrayList<>();

        for (Long roleId : req.getRoleIds()) {
            SysUserRoleEntity sysUserRoleEntity = new SysUserRoleEntity();
            sysUserRoleEntity.setUserId(req.getUserId());
            sysUserRoleEntity.setRoleId(roleId);
            list.add(sysUserRoleEntity);
        }
        sysUserRoleService.addUserRoles(req.getUserId(), list);
    }

    /**
     * 用户登录认证
     *
     * <p>校验用户名与密码，生成 JWT Token 并返回。</p>
     *
     * @param req 登录请求参数（用户名、密码）
     * @return 用户信息及角色、权限信息与 Token
     * @throws VehicleAccessException 当用户名或密码错误时抛出
     */
    @Override
    public SysUserRes login(UserLoginReq req) {

        // 1. 根据用户名查询用户信息（验证用户是否存在）
        SysUserRes sysUserRes = new SysUserRes();
        SysUserEntity sysUserEntity = sysUserService.getUserByUsername(req.getUsername());

        // 若用户不存在，则抛出“用户不存在”业务异常
        if (sysUserEntity == null) {
            throw VehicleAccessException.DATE_NOT_EXIST.newInstance("用户不存在");
        }

        // 2. 校验密码是否正确（此处使用明文对比，生产环境建议使用加密验证）
        if (!StrUtil.equals(req.getPassword(), sysUserEntity.getPassword())) {
            throw VehicleAccessException.PASSWORD_ERROR;
        }

        // 3. 生成 JWT Token，用于后续请求的身份认证
        String token = generateToken(sysUserEntity.getUsername(), sysUserEntity.getId());
        sysUserRes.setToken(token);

        // 将数据库中的用户基本信息拷贝到返回对象（不包含角色与权限）
        BeanUtils.copyProperties(sysUserEntity, sysUserRes);

        // 4. 查询用户关联的角色与权限信息，用于前端展示与权限控制
        UserInfo userInfo = sysUserService.getUserRoleAndPermission(sysUserEntity.getId());

        // 将角色实体对象转换为响应对象 SysRoleRes
        List<SysRoleRes> sysRoleResList = userInfo.getRoleEntityList().stream().map(sysRoleEntity -> {
            SysRoleRes sysRoleRes = new SysRoleRes();
            BeanUtils.copyProperties(sysRoleEntity, sysRoleRes);
            return sysRoleRes;
        }).toList();

        // 将权限实体对象转换为响应对象 SysPermissionRes
        List<SysPermissionRes> sysPermissionResList = userInfo.getPermissionEntityList().stream().map(sysPermissionEntity -> {
            SysPermissionRes sysPermissionRes = new SysPermissionRes();
            BeanUtils.copyProperties(sysPermissionEntity, sysPermissionRes);
            return sysPermissionRes;
        }).toList();

        // 5. 设置用户的角色与权限集合到返回对象中
        sysUserRes.setSysRoleResList(sysRoleResList);
        sysUserRes.setSysPermissionResList(sysPermissionResList);
        // 返回完整的登录响应对象（包含用户信息、角色、权限、Token）
        return sysUserRes;
    }

    /**
     * 生成用户登录 Token
     *
     * @param username 用户名
     * @param id 用户ID
     * @return 加密后的 JWT Token
     */
    private String generateToken(String username, Long id) {

        JWTSigner jwtSigner = JWTSignerUtil.hs256(systemConfigService.get(SystemConfig.jwtSecurityKey).getBytes());

        Integer expireTime = systemConfigService.get(SystemConfig.jwtTokenExpireTime);
        return JWT.create()
                .setExpiresAt(new Date(System.currentTimeMillis() + expireTime))
                .setPayload("username", username)
                .setPayload("userId", id)
                .sign(jwtSigner);
    }


    /**
     * 校验用户是否存在
     *
     * @param id 用户主键ID
     * @return 存在的用户实体
     * @throws VehicleAccessException 用户不存在时抛出
     */
    private SysUserEntity checkUserExist(Long id) {
        SysUserEntity sysUserEntity = sysUserService.getUserById(id);

        if (sysUserEntity == null) {
            throw VehicleAccessException.DATE_NOT_EXIST.newInstance("用户不存在");
        }

        return sysUserEntity;
    }


}
